from parser import Parser
import os
from ftp import FtpServer
from prompt_toolkit import PromptSession, prompt
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.application import run_in_terminal
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from click import Context, OptionParser, echo, core, Command, Argument, Option
import time
import re
from math import floor

commands = {}
cmds = []


class Core:
    _flag_needs_value = []


def register_command(command: dict, args: list[dict] = [], options:  list[dict] = [], callback=None):
    com = Command(**command)
    context = Context(command=com, allow_interspersed_args=True,
                      allow_extra_args=True, ignore_unknown_options=True, help_option_names=["-h", "--help"])

    cmd = OptionParser(context)

    for arg in args:
        cmd.add_argument(**arg)
    for option in options:
        cmd.add_option(Core, **option)

    commands[command.get("name")] = (args, options, callback)
    cmds.append((command.get("name"), cmd, callback))
    return cmd


binding = KeyBindings()


@binding.add('c-c')
def _(event):
    print("\n再见!")
    exit(0)


class Cli:

    ftp = None

    def __init__(self, host, port):
        self.connect(host, port)
        self.next_one()

    def fetch_prefix(self):
        return self.ftp.pwd + ">"

    def connect(self, host, port):
        self.ftp = FtpServer(host, port)

    def next_one(self):
        session = PromptSession(
            key_bindings=binding, auto_suggest=AutoSuggestFromHistory())
        while True:
            text = session.prompt(self.fetch_prefix() or "")
            if text == "" or text == None:
                continue

            self.match_command(text)

    def match_command(self, text: str):
        match = None
        # 根据前缀匹配是否注册了改命令
        for name, cmd, callback in cmds:
            if text.startswith(name):
                match = (name, cmd, callback)

        if match == None:
            print("Command Not Found")
            return

        name, cmd, callback = match
        strcmd = text[len(name) + 1:]
        if strcmd == '':
            strcmd = []
        else:
            # 解析器解析解析器可分析的列表
            # 库是真的拉呀，解析参数你都写出来了，解析字符串你不做
            parser = Parser(strcmd)
            strcmd = parser.parse()

        args = cmd.parse_args(strcmd)

        _, not_match, _ = args
        helps_names = set(cmd.ctx.help_option_names)
        if len(list(filter(lambda flag: helps_names.issubset(flag), not_match))) > 0:
            print(cmd.ctx.get_help())
            return

        if callback != None:
            callback(self, args)


def ls(ctx: Cli, args: (dict, list, list)):
    arg, _, _ = args
    res = None
    if not ctx.ftp.is_connect():
        print("请连接服务器后再试")
        return

    if arg.get("isFile") == True:
        res = ctx.ftp.get_list_of_type("file")
    elif arg.get("isDir") == True:
        res = ctx.ftp.get_list_of_type("dir")
    elif arg.get("file") != None:
        current_dirname = ctx.ftp.pwd
        dirname = os.path.join(current_dirname, arg.get("file"))
        ctx.ftp.change_dir(dirname)
        res = ctx.ftp.get_list_of_type()
        ctx.ftp.change_dir(current_dirname)
    else:
        res = ctx.ftp.get_list_of_type()

    if res == None:
        print("无结果")
        return
    terminal_width = os.get_terminal_size().columns

    margin = 10
    count = 0
    for name, info in res:
        d = 'D' if info.get('type') == 'dir' else 'F'
        s = "{} {}".format(d, name)
        print(s)


def app_exit(ctx: Cli, args):
    try:
        ctx.ftp.quit()
    except:
        pass
    print("再见~")
    exit()


def connect(ctx: Cli, args: (dict, list, list)):
    arg, _, _ = args
    print(arg)
    host = arg.get("host")
    port = arg.get("port")
    ctx.ftp = FtpServer(host, port)


def find_file(ctx: Cli, args: (dict, list, list)):
    arg, _, _ = args

    filename: str = arg.get("filename")
    only_file = arg.get("file")
    only_dir = arg.get("dir")

    if (filename == None):
        print("请输入过滤条件")
        return

    res = None
    if only_file == True:
        res = ctx.ftp.get_list_of_type("file")
    elif only_dir == True:
        res = ctx.ftp.get_list_of_type("dir")
    else:
        res = ctx.ftp.get_list_of_type()

    for name, info in res:
        if name.find(filename) != -1:
            d = 'D' if info.get('type') == 'dir' else 'F'
            s = "{} {}".format(d, name)
            print(s)

from scripts.diff import diff

register_command(
    {
        'name': 'diff',
        'help': '对比本文件夹下文件与指定名字集合的不同'
    },
    [
        {
            'obj': 'filename',
            'dest': 'filename',
            "nargs": 1,
        }
    ],
    [
        {
            'opts': ["-d", "--deep"],
            'dest': 'deep',
            'action': 'store_const',
            'const': True
        },
        {
            'opts': ["-n", "--name"],
            'dest': 'name',
            'action': 'store',
        },
    ],
    callback=diff
)


def cd(ctx: Cli, args: (dict, list, list)):
    arg, _, _ = args
    dirname = arg.get("dirname")
    if (dirname == None):
        ctx.ftp.change_dir(ctx.ftp.root)
        return
    ctx.ftp.change_dir(dirname)


register_command(
    {
        'name': 'cd',
        'help': '切换目录'
    },
    [
        {
            "obj": "dirname",
            "dest": "dirname",
            "nargs": 1,
        },
    ],
    callback = cd
)

register_command(
    {'name': "connect", "help": "连接服务器"},
    options=[
        {
            "opts": ["-P", "--port"],
            "dest": "port",
            "action": "store",
        },
        {
            "opts": ["-h", "--host"],
            "dest": "host",
            "const": 21
        }
    ],
    callback=connect
)

register_command(
    {'name': "ls", 'help': "显示当前目录文件"},
    [{'obj': 'file', 'dest': "file"}],
    [
        {
            'opts': ["-f", "--file"],
            'dest': "isFile",
            'action': "store_const",
            'const': True
        },
        {
            'opts': ["-d", "--dir"],
            'dest': "isDir",
            'action': "store_const",
            'nargs': 1,
            'const': True
        },
    ],
    ls
)

register_command({'name': "exit", 'help': '关闭程序 '}, callback=app_exit)


register_command(
    {
        'name': "find",
        'help': '寻找某个文件'
    },
    [
        {
            "obj": "filename",
            "dest": "filename",
            "nargs": 1,
        },
    ],
    [
        {
            'opts': ["-f", "--file"],
            'dest': "file",
            'action': "store_const",
            'const': True
        },
        {
            'opts': ["-d", "--dir"],
            'dest': "dir",
            'action': "store_const",
            'const': True
        },
    ],
    callback=find_file
)

